package com.pernix.authen.network;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.sql.SQLException;
import java.text.MessageFormat;
import java.util.UUID;

import net.jradius.util.RadiusRandom;

import com.pernix.authen.MSCHAP;
import com.pernix.authen.jdbchelper;
import com.pernix.authen.model.AuthenUser;
import com.pernix.authen.net.ChatMessage;
import com.pernix.authen.util.DisplayUtil;
import com.pernix.log.ILog;

public class AuthenClientRunnable implements Runnable {
	private Socket socket;
	private ObjectOutputStream sOutput;
	private ObjectInputStream sInput;
    private UUID threadId;
    private ILog logger;
    private byte[] authChallenge;
    private byte[] challengeResponse;
    private byte[] peerChallenge;
    private String username;
    private String password;
    private String usernameAtDB;
    private String passwordAtDB;
    private AuthenUser autheUserInfo;
	public AuthenClientRunnable(ILog logger, Socket socket) {
		this.socket = socket;
		this.logger = logger;
		this.threadId = UUID.randomUUID();
		try {
			sOutput = new ObjectOutputStream(socket.getOutputStream());
			sInput = new ObjectInputStream(socket.getInputStream());

		} catch (IOException e) {
			// TODO Auto-generated catch block
			System.out.println(e.getMessage());
			//e.printStackTrace();
		}
	}

	public void stop() {
		try {
			if (sOutput != null) {
				sOutput.close();
			}
			if (sInput != null) {
				sInput.close();
			}
			Thread.currentThread().interrupt();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	private void sendMessage(AuthenMessage authenMessage){
		try {
			sOutput.writeObject(authenMessage);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	@Override
	public void run() {
		while (!Thread.currentThread().isInterrupted()) {
			AuthenMessage authenMsg = null;
			try {
				authenMsg = (AuthenMessage) sInput.readObject();
			} catch (ClassNotFoundException | IOException e) {
				Thread.currentThread().interrupt();
			}
			if(authenMsg!=null){
				switch (authenMsg.authenMessageType) {
				case REQUEST_CHALLENGE:
					logger.Debug(" Step 02: Receive Request Authen From Client");
					authChallenge = RadiusRandom.getBytes(16);
					String usernameFromClient = authenMsg.message;
					autheUserInfo = null;
					String salt = "";
					try {
						autheUserInfo =  jdbchelper.Authentication(usernameFromClient);
						if(autheUserInfo!=null){
						salt = autheUserInfo.getSalt();
						}
						logger.Debug(" Step 02: Generate [16Bytes] ServerChallenge " + DisplayUtil.print(authChallenge));
						logger.Debug(" Step 02: Send ServerChallenge to Client.");
						
					} catch (SQLException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					sendMessage(new AuthenMessage(AuthenMessageType.RESPONSE_CHALLENGE, authChallenge, null, null, salt));
					break;
				case REQUSET_AUTHEN:
					challengeResponse = authenMsg.serverChallenge;
					peerChallenge = authenMsg.peerChallenge;
					username = authenMsg.username;
					//password = authenMsg.password;
					
					if(autheUserInfo!=null){
						usernameAtDB = autheUserInfo.getUsername();
						passwordAtDB = autheUserInfo.getPasshash();
					}else{
						usernameAtDB = "";
						passwordAtDB = "";
					}
					
					System.out.print("========>" + username + " " + password + "\n");
					
					logger.Debug(" Step 04: Receive Request AuthenResponse From Client");
					boolean success = MSCHAP.verifyMSCHAPv2(usernameAtDB.getBytes(), passwordAtDB.getBytes(), authChallenge, challengeResponse);
					logger.Debug(" Step 04: Verify ChallengeResponse from Client is ====> " + success);
					logger.Debug(" Step 04: Create AuthenResponse");
					
					
					byte[] authenResComputeAtServer = MSCHAP.getAuthenResponse(authChallenge, peerChallenge, usernameAtDB.getBytes(), passwordAtDB.getBytes());
					logger.Debug(" Step 04: Send AuthenResponse to Client" + DisplayUtil.print(authenResComputeAtServer));
					sendMessage(new AuthenMessage(AuthenMessageType.RESPONSE_AUTHEN, authenResComputeAtServer));
					stop();
					break;
				default:
					break;
				}
			}
		}
	}
}
